"""
得到生成器的方式：
1.通过列表推导式得到生成器
2.借助函数＋yield得到生成器
"""

# 得到列表[0,3,6,9,12,15,18,...27]
# 使用列表推导式
newlist = [x * 3 for x in range(10)]
print(newlist)
print(type(newlist))

# 使用生成器
g = (x * 3 for x in range(10))
print(type(g))
print(g)

# 方式1：通过调用__next__()方式来依次得到元素
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())

# 方式2：通过系统内置的next函数来依次得到元素,next(生成器对象)
# 每调用一次next则会产生一个元素
print(next(g))
print(next(g))
print(next(g))
print(next(g))

# 对生成器进行循环操作
g = (x * 3 for x in range(10))

while True:
    try:
        e = next(g)
        print(e)
    except:
        print("没有更多元素啦！")
        break

"""
步骤：
1.定义一个函数，函数中使用yield关键字
2.调用函数，接收调用的结果
3.得到的结果就是生成器
4.借助与next(),__next__()得到元素
"""


# 只要函数中出现了yield关键字，说明函数就变成了生成器
def func():
    n = 0
    while True:
        n += 1
        # print(n)
        yield n  # yield起到了一个return＋stop的作用


g1 = func()
print(g1)  # 打印输出的是生成器对象
print(next(g1))


# 生成斐波那契数列
def fib(length):
    a, b = 0, 1
    count = 0

    while count < length:
        yield b  # 输出当前的b值，它是数列的下一个数字
        a, b = b, a + b
        count += 1
    return "没有更多元素了！"  # 在生成器中的返回值通常是对异常的提示信息


g2 = fib(8)  # <generator object func at 0x0000021CE6E25600>
print(next(g2))
print(next(g2))
print(next(g2))
print(next(g2))
# print(next(g2))
# print(next(g2))
# print(next(g2))
# print(next(g2))
# print(next(g2))
# print(next(g2))         # 调用次数超过生成器数据就会报StopIteration错
print("\n")

"""
生成器方法：
    __next__(): 获取下一个元素
    send(value):向每次生成器调用中传值，注意第一次调用必须send(None)
    next(generator) ---> 每次调用都会产生一个新的元素，如果元素产生完毕，再次调用的话就会产生异常
"""


def gen():
    i = 0
    while i < 5:
        temp = yield i  # return 1 + 暂停
        print("temp:", temp)
        for x in range(temp):
            print("------->", x)
        print("*****************")
        i += 1
    return "没有更多的数据"


g3 = gen()
print(g3.send(None))
n1 = g3.send(3)
print("n1:", n1)
n2 = g3.send(5)
print("n2:", n2)


# 进程 > 线程 > 协程(生成器应用场景)

# 进行协程（任务一起运行）操作
def task_1(n):
    for i in range(n):
        print(f"正在搬第{i}块砖！")
        yield None  # 将任务转化为生成器对象（暂停输出）,就可以自定义输出顺序


def task_2(n):
    for i in range(n):
        print(f"正在听第{i}首歌！")
        yield None


g4 = task_1(5)
g5 = task_2(5)

while True:
    try:
        g4.__next__()
        g5.__next__()
    except:
        break  # 防止程序死循环